package com.jl15988.chainlog.aspect;

import com.jl15988.chainlog.annotation.ChainCustom;
import com.jl15988.chainlog.annotation.ChainDisabled;
import com.jl15988.chainlog.annotation.ChainMethod;
import com.jl15988.chainlog.callback.ChainMethodCallback;
import com.jl15988.chainlog.config.ChainLogProperties;
import com.jl15988.chainlog.context.ChainLogContext;
import com.jl15988.chainlog.model.ChainApiLog;
import com.jl15988.chainlog.model.ChainMethodLog;
import com.jl15988.chainlog.util.AspectUtil;
import com.jl15988.chainlog.util.ExceptionUtil;
import com.jl15988.chainlog.util.IdUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * 链式监控切面
 */
@Aspect
@Order(2)
@Slf4j
public class ChainMethodAspect {

    @Autowired
    private ChainLogProperties chainLogProperties;

    @Autowired(required = false)
    private List<ChainMethodCallback> callbacks;

    /**
     * 链式监控切点
     */
    @Pointcut("@annotation(com.jl15988.chainlog.annotation.ChainMethod)")
    public void chainMonitorPointcut() {
    }

    /**
     * 环绕通知
     */
    @Around("chainMonitorPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Date startTime = new Date();
        // 检查是否启用监控
        if (!chainLogProperties.isEnabled()) {
            return joinPoint.proceed();
        }

        // 检查是否在接口监控上下文中
        ChainApiLog chainApiLog = ChainLogContext.getChainApiLog();
        if (chainApiLog == null) {
            return joinPoint.proceed();
        }

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Class<?> targetClass = joinPoint.getTarget().getClass();

        // 检查是否有NoMonitor注解
        if (method.isAnnotationPresent(ChainDisabled.class) || targetClass.isAnnotationPresent(ChainDisabled.class)) {
            return joinPoint.proceed();
        }

        ChainMethod chainMethod = method.getAnnotation(ChainMethod.class);
        if (chainMethod == null) {
            return joinPoint.proceed();
        }

        // 创建链式监控信息
        ChainMethodLog parentChainInfo = ChainLogContext.getCurrentChainMethodLog();
        String parentId = parentChainInfo != null ? parentChainInfo.getId() : chainApiLog.getId();

        ChainMethodLog chainMethodLog = createChainMethodLog(parentId, method, targetClass, chainMethod, startTime, joinPoint);
        ChainLogContext.pushChainMethodLog(chainMethodLog);

        Object result = null;
        Throwable exception = null;

        try {
            // 执行目标方法
            result = joinPoint.proceed();

            // 记录返回值
            chainMethodLog.setResult(result);
            chainMethodLog.setSuccess(true);
        } catch (Throwable e) {
            exception = e;
            chainMethodLog.setSuccess(false);

            // 记录异常信息
            chainMethodLog.setExceptionInfo(ExceptionUtil.getExceptionStackTrace(e));
            throw e;
        } finally {
            // 完成监控信息
            completeChainLog(chainMethodLog);
            // 弹出当前监控信息
            ChainLogContext.popChainMethodLog();
            // 执行回调
            executeCallbacks(chainMethodLog, chainApiLog, parentChainInfo, exception);
        }

        return result;
    }

    /**
     * 创建链式监控信息
     */
    private ChainMethodLog createChainMethodLog(String parentId, Method method,
                                                Class<?> targetClass, ChainMethod chainMethod, Date startTime, ProceedingJoinPoint joinPoint) {
        ChainMethodLog chainMethodLog = new ChainMethodLog(IdUtil.generateId(), parentId, startTime);

        // 基本信息
        chainMethodLog.setLevel(ChainLogContext.getCurrentLevel() + 1);

        chainMethodLog.setMethod(targetClass.getName() + "." + method.getName());
        chainMethodLog.setClassName(targetClass.getName());

        // 构建参数
        Map<String, Object> params = AspectUtil.getParams(joinPoint);
        chainMethodLog.setParams(params);

        // 注解信息
        chainMethodLog.setName(chainMethod.name() == null || chainMethod.name().isEmpty() ? method.getName() : chainMethod.name());
        chainMethodLog.setDesc(chainMethod.desc());

        // 构建自定义参数
        Map<String, String> customParams = new HashMap<>();
        ChainCustom[] customs = chainMethod.customs();
        if (customs != null) {
            for (ChainCustom chainCustom : customs) {
                customParams.put(chainCustom.key(), chainCustom.value());
            }
        }
        chainMethodLog.setCustoms(customParams);

        return chainMethodLog;
    }

    /**
     * 完成链式监控信息
     */
    private void completeChainLog(ChainMethodLog chainInfo) {
        Date endTime = new Date();
        chainInfo.setEndTime(endTime);
        chainInfo.setDuration(endTime.getTime() - chainInfo.getStartTime().getTime());

        // 截断过长的参数
//        if (chainInfo.getParams() != null) {
//            String paramsStr = MonitorUtils.toJsonString(chainInfo.getParams());
//            paramsStr = MonitorUtils.truncateString(paramsStr, monitorProperties.getMaxParamLength());
//            chainInfo.setParams(new Object[]{paramsStr});
//        }
//
//        if (chainInfo.getResult() != null) {
//            String resultStr = MonitorUtils.toJsonString(chainInfo.getResult());
//            resultStr = MonitorUtils.truncateString(resultStr, monitorProperties.getMaxParamLength());
//            chainInfo.setResult(resultStr);
//        }
    }

    /**
     * 执行回调
     */
    private void executeCallbacks(ChainMethodLog chainInfo, ChainApiLog chainApiLog,
                                  ChainMethodLog parentChainInfo, Throwable exception) {
        if (callbacks == null || callbacks.isEmpty()) {
            return;
        }

        // 异步执行回调
        CompletableFuture.runAsync(() -> {
            for (ChainMethodCallback callback : callbacks) {
                try {
                    if (exception != null) {
                        callback.onChainException(chainInfo, chainApiLog, parentChainInfo, exception);
                    } else {
                        callback.onChainComplete(chainInfo, chainApiLog, parentChainInfo);
                    }
                } catch (Exception e) {
                    // 记录回调异常，但不影响主流程
                    log.warn(e.getMessage(), e);
                }
            }
        });
    }
}